#include <stdio.h>
#include <stdlib.h>
#include "memory.h"
#include "fiber.h"


Schedule schedule_make() {
	Schedule result = (Schedule) memory_make(Schedule);
	result->last 	= 0;
	result->max  	= SCHEDULE_FIBER_MAX;
	result->active 	= 0;
	result->running = NULL;
	return result;
}

Schedule schedule_free(Schedule self) {
	memory_free(self);
	return NULL;
}

Schedule schedule_add_fiber(Schedule self, Fiber fiber) {
	self->fibers[self->last] = fiber;
	self->last++;
	self->active++;
	return self;
}

Fiber fiber_make(Fiber_action action, Schedule schedule ) {
	Fiber fiber = (Fiber) memory_make(Fiber); 
	fiber->action 	= action;
	fiber->schedule = schedule;
	fiber->state 	= FIBER_SLEEP; 
	return fiber;
}

Fiber fiber_free(Fiber self) {
	memory_free(self); 
	return NULL;
}

Fiber schedule_add_action(Schedule self, Fiber_action action) {
	Fiber fiber = fiber_make(action, self);
	schedule_add_fiber(self, fiber);
	return fiber;
}

Schedule schedule_run_once(Schedule self) {
	int index;
	Fiber fiber;
	Fiber result;
	Fiber_action action;
	
	for(index = 0 ; index < self->last ; index ++) {
		self->active = index;
		fiber 		 = self->fibers[index];
		if(fiber->state == FIBER_DONE) {
			continue; 
			/* Skip over threads that are done. */
		}
		
		action 		 = fiber->action;
		result 		 = action(fiber);
		if(result->state == FIBER_DONE) {
			self->active--;
		}
	}
	return self;
}

int schedule_done(Schedule self) {
	return (self->active < 0);
} 


Schedule schedule_run(Schedule self) {
	int done = 1;
	do {
		schedule_run_once(self);
		done = schedule_done(self);
	} while (! done);
	return self;
}


Fiber fiber_yield_helper(Fiber self, Fiberstate state, void * result) {
	self->state = state;
	if(result) self->result = result;
	return self;
}


#define fiber_yield(fiber) \
		do { return fiber_yield_helper(fiber, FIBER_SLEEP, 0 ); } while (0)
#define fiber_return(fiber, result) \
		do { return fiber_yield_helper(fiber, FIBER_DONE, RESULT ); } while (0)


#undef TEST_FIBER_C
#ifdef TEST_FIBER_C




int main(int argc, char * argv[]) {
	Schedule schedule = schedule_make();
	
	return 0;
}


#endif
